/*************************************************** File: SearchResultsWorld.java Author: Hermes Roferos Created: October 21, 1999 Last Modified: 11/3/99 HRR: added collection retrieval functionality 10/29/99 - Scott - Adapt for SearchResult collection ***************************************************/ import vrml.*; import vrml.field.*; import vrml.node.*; import java.util.Date; import java.net.*; /** * Class to obtain search results from the SearchResultsCollector then create graphical nodes * (the fishes) which have parameters determined by the results. Each fish displayed is a search * hit with the document title displayed on the side of the fish. The document url and high-level * domain name determine the fish's body and fin colors respectively. The age of the document * determines the speed that the fish swims at, and the document hit ranking determines the level * in the y-axis where the fish is located. */ public class SearchResultsWorld extends Script { private SFString queryText; private MFNode newNode; private Browser clientBrowser; private SFTime getNextResult; private SFBool isRunning; private int nextResultIndex = 0; private SearchResultsCollector theCollector; /** * Initialization method. Routes VRML fields and events to internal attributes. Obtains * the query text from the VRML world and calls the SearchResultsCollector with it. */ public void initialize() { vrml.external.Browser.print( "Getting Fields"); // get a reference to the childList script event queryText = (SFString)getField( "queryText"); vrml.external.Browser.print( "getting newNode event"); newNode = (MFNode)getEventOut( "newNode" ); vrml.external.Browser.print( "getting getNextResult event"); getNextResult = (SFTime)getEventIn( "getNextResult"); vrml.external.Browser.print( "getting isRunning event"); isRunning = (SFBool)getEventOut( "isRunning"); // get a reference to the client browser vrml.external.Browser.print( "getting browser"); clientBrowser = this.getBrowser(); theCollector = new SearchResultsCollector(); theCollector.setQueryText( queryText.getValue() ); theCollector.start(); } /** * Method called every time an event occurs. Currently this method only looks at events * generated by the getNextResult eventIN field in the VRML world. Once the event is * received, this method calls the generateNode() method to create the search result nodes. */ public void processEvent( Event e ) { if ( e.getName().equals( "getNextResult" ) ) { if ( theCollector.getState() == theCollector.S_Done ) { if ( theCollector.getCount() > 0 ) { try { generateNode( theCollector.getSearchResult( nextResultIndex++ ) ); } catch( InvalidVRMLSyntaxException ex ) { vrml.external.Browser.print( ex.getMessage() ); } } } } } /** * Method to generate the VRML search results node (in the form of a fish) using the document * information that is obtained from the search. The following are the node attributes: * - Document Title = String displayed on the side of the fish * - Document age = How fast the fish swims * - High-level domain name of site containing the document = color of the fish fins and tail * - IP address of the site = color of the fish body * - Search ranking - y-axis coordinate where the fish is placed. */ private void generateNode( SearchResult r ) throws InvalidVRMLSyntaxException { vrml.external.Browser.print( "Generating Node for " + r.getTitle() ); StringBuffer vrmlString = new StringBuffer(); MFNode nodes = new MFNode(); // create the VRML string to display the search result vrmlString.append( "EXTERNPROTO SearchResultNode [" + " field MFString title" + " field SFTime age" + " field SFColor hostIP" + " field SFColor domainName" + " ] \"SearchResultNode.wrl\"" ); // the fish's text is the document title String title = r.getTitle(); // calculate age of a document to determine how fast the fish swims // the # of mS in a month is: 1000 mS * 60 secs * 60 min * 24 hours * 7 days * 4 weeks // each month older, the cycle time goes up by 1 with a minimum cycle time of 6 Date today = new Date(); Date docDate = r.getLastModifiedDate(); double elapsedMonths = (double)( today.getTime() - docDate.getTime() ) / (1000.0*60.0*60.0*24.0*7.0*4.0 ); if ( elapsedMonths < 6 ) elapsedMonths = 6; String age = Double.toString( elapsedMonths ); // Calculate the color of the fish's fins // determinge the high-level domain and convert it to an RGB value // rgb color is the char's relative position in the alphabet String alphabet = "abcdefghijklmnopqrstuvwxyz"; double[] rgb = new double[3]; rgb[2] = 0.0; // default blue component = 0 in case it is only a 2-char domain URL docUrl = r.getURL(); String host = docUrl.getHost().toLowerCase(); String hLevelDomain = host.substring( host.lastIndexOf( '.' ) + 1 ); int hLDnameLength = hLevelDomain.length(); if ( hLDnameLength > 3 ) // for this purpose, we limit it to 3 characters hLDnameLength = 3; for ( int i = 0 ; i < hLDnameLength ; i++ ) rgb[i] = (double)alphabet.indexOf( hLevelDomain.charAt( i ) ) / 26.0; String finColor = " " + Double.toString( rgb[0] ) + " " + Double.toString( rgb[1] ) + " " + Double.toString( rgb[2] ) + " "; vrml.external.Browser.print( "tail/fin RGB: " + finColor ); // fish's body color rgb values are the first 3 numbers in the ip address divide by 255 byte[] ipAddr = new byte[4]; try { vrml.external.Browser.print( "Looking up address of " + host ); InetAddress hostAddress = InetAddress.getByName( host ); ipAddr = hostAddress.getAddress(); } catch ( Exception ex ) { vrml.external.Browser.print( "Unable to get address for " + host ); // if can't get the ip address, make the fish red ipAddr[0] = (byte)200; ipAddr[1] = ipAddr[2] = (byte)0; } for ( int i = 0 ; i < 3 ; i++ ) // cast to a char first because bytes are signed 2's complement; mask out upper 8 bits rgb[i] = (double)( (char)ipAddr[i] & 0xff ) / 255.0; String bodyColor = " " + Double.toString( rgb[0] ) + " " + Double.toString( rgb[1] ) + " " + Double.toString( rgb[2] ) + " "; vrml.external.Browser.print( "Body RGB: " + bodyColor ); // use document rank for the y location of the fish int docRank = r.getRank(); // now set the calculated values into search result node parameters vrmlString.append( "Transform { translation 0 -" + Integer.toString( docRank * 3) +" 0 " + " children [ " + " SearchResultNode {" + " title \"" + title + "\"" + " age " + age + " hostIP " + bodyColor + " domainName " + finColor + " } ] }" ); // create VRML and attach it to the target node newNode.setValue( clientBrowser.createVrmlFromString( vrmlString.toString() ) ); } }